// 4.5 递增和递减运算符
/**
 * 递增和递减运算符有两种形式：前置版本和后置版本。
 */

#include <vector>
#include <iostream>

int main(int argc, char const *argv[])
{
    // 到目前为止，本书使用的都是前置版本，这种形式的运算符首先将运算对象加1（或减1），然后将改变后的对象作为求值结果。
    // 后置版本也会将运算对象加1（或减1），但是求值结果是运算对象改变之前那个值的副本：
    int i=0, j;
    j = ++i;  // j=1, i=1，前置版本得到递增之后的值
    j = i++;  // j=1, i=2，后置版本得到递增之前的值
    // 这两种运算符必须作用于左值运算对象。前置版本将对象本身作为左值返回，后置版本则将对象原始值的副本作为右值返回。

    // ***********建议：除非必须，否则不用递增递减运算符的后置版本*************
    // 前置版本的递增运算符避免了不必要的工作，它把值加1后直接返回改变了的运算对象。与之相比，后置版本需要将原始值存储下来以便于返回这个未修改的内容。
    // 如果我们不需要修改前的值，那么后置版本的操作就是一种浪费。
    // 对于整数和指针类型来说，编译器可能对这种额外的工作进行一定的优化；但是对于相对复杂的迭代器类型，这种额外的工作就消耗巨大了。
    // ***********建议养成使用前置版本的习惯，这样不仅不需要担心性能的问题，而且更重要的是写出的代码会更符合编程的初衷。*************

    // 在一条语句中混用解引用和递增运算符
    // 如果我们想在一条复合表达式中既将变量加1或减1又能使用它原来的值，这时就可以使用递增和递减运算符的后置版本。
    std::vector<int> v = {1,2,3,4,5,6,7,8,9,10};
    auto pbeg = v.begin();
    while (pbeg != v.end() && *pbeg > 0)
        std::cout << *pbeg++ << std::endl; // 输出当前值并将pbeg向右移动一个元素
    // 对于刚接触C++和C的程序员来说，＊pbeg++不太容易理解。其实这种写法非常普遍，所以程序员一定要理解其含义。
    // 后置递增运算符的优先级高于解引用运算符，因此＊pbeg++等价于＊(pbeg++)。pbeg++把pbeg的值加1，然后返回pbeg的初始值的副本作为其求值结果，此时解引用运算符的运算对象是pbeg未增加之前的值。
    // 最终，这条语句输出pbeg开始时指向的那个元素，并将指针向右移动一个位置。

    // 建议：简洁可以成为一种美德
    // 形如＊pbeg++的表达式一开始可能不太容易理解，但其实这是一种被广泛使用的、有效的写法。当对这种形式熟悉之后，书写就会变得简洁。
    // 不断研究这样的例子直到对它们的含义一目了然。大多数C++程序追求简洁、摒弃冗长，因此C++程序员应该习惯于这种写法。而且，一旦熟练掌握了这种写法后，程序出错的可能性也会降低。

    return 0;
}
